/**
 * @file sensor_read.c
 * @brief 传感器读取相关
 */

/*********************
 *      INCLUDE
 *********************/
//导入库
#include <windows.h>
#include <stdio.h>
//导入自定义头文件
#include "sensor_read.h"
#include "sport.h"
#include "utf-8_to_gbk.h"

/*********************
 *      DEFINES
 *********************/
#define SERIAL_PORT "COM6"           // 串口端口
#define BAUD_RATE CBR_9600           // 波特率
#define MOTION_THRESHOLD_COUNT 15    // 连续15次运动触发弹窗


/**********************
 *  STATIC VARIABLES
 **********************/
int16_t sim_AX = 0, sim_AY = 0, sim_AZ = 0, sim_GX = 0, sim_GY = 0, sim_GZ = 0;
uint8_t sim_motion_state = 0;
uint32_t sim_motion_counter = 0;
uint32_t motion_detect_counter = 0;  // 连续运动检测计数器
uint32_t consecutive_motion_count = 0; // 连续运动计数
bool motion_popup_triggered = false;   // 弹窗触发标志

// 串口相关变量
static HANDLE hSerial = INVALID_HANDLE_VALUE;
static DCB dcbSerialParams = {0};
static COMMTIMEOUTS timeouts = {0};

extern void trigger_motion_popup(void);

// 添加重试相关变量
static uint32_t serial_retry_timeout = 0;
static const uint32_t SERIAL_RETRY_INTERVAL = 5000; // 5秒重试一次

// 在文件开头添加声明
extern bool is_motion_popup_in_cooldown(void);
extern uint32_t get_remaining_cooldown_seconds(void);

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

/**
 * @brief 初始化串口
 * @return 成功返回true，失败返回false
 */
bool init_serial_port(void)
{
    // 打开串口
    hSerial = CreateFileA(SERIAL_PORT,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         NULL,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         NULL);

    if (hSerial == INVALID_HANDLE_VALUE) {
        printf("[SERIAL] 无法打开串行端口 %s\n", SERIAL_PORT);
        return false;
    }

    // 获取当前串口参数
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        printf("[SERIAL] 未能获取串口状态\n");
        CloseHandle(hSerial);
        return false;
    }

    // 配置串口参数
    dcbSerialParams.BaudRate = BAUD_RATE;     // 波特率
    dcbSerialParams.ByteSize = 8;             // 数据位
    dcbSerialParams.StopBits = ONESTOPBIT;    // 停止位
    dcbSerialParams.Parity = NOPARITY;        // 校验位
    dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; // 启用DTR

    if (!SetCommState(hSerial, &dcbSerialParams)) {
        printf("[SERIAL] 无法设置串行端口参数\n");
        CloseHandle(hSerial);
        return false;
    }

    // 设置串口超时
    timeouts.ReadIntervalTimeout = 50;        // 读取间隔超时
    timeouts.ReadTotalTimeoutConstant = 50;   // 读取总超时常数
    timeouts.ReadTotalTimeoutMultiplier = 10; // 读取总超时乘数
    timeouts.WriteTotalTimeoutConstant = 50;  // 写入总超时常数
    timeouts.WriteTotalTimeoutMultiplier = 10;// 写入总超时乘数

    if (!SetCommTimeouts(hSerial, &timeouts)) {
        printf("[SERIAL] 超时未能设置串行端口\n");
        CloseHandle(hSerial);
        return false;
    }

    // 清空串口缓冲区
    PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);

    printf("[SERIAL] 串行端口 %s 成功被初始化. 波特率:%d\n", SERIAL_PORT, BAUD_RATE);
    return true;
}

/**
 * @brief 关闭串口
 */
void close_serial_port(void)
{
    if (hSerial != INVALID_HANDLE_VALUE) {
        CloseHandle(hSerial);
        hSerial = INVALID_HANDLE_VALUE;
        printf("[SERIAL] 串行端口已关闭.\n");
    }
}

/**
 * @brief 从串口读取运动数据
 * @return 运动状态 (0:静止, 1:运动)
 */
uint8_t read_serial_motion_data(void)
{
    // 如果串口未初始化，尝试重新初始化
    if (hSerial == INVALID_HANDLE_VALUE) {
        static uint32_t last_retry_time = 0;
        uint32_t current_time = GetTickCount();

        // 每隔一段时间重试一次，避免频繁重试
        if (current_time - last_retry_time > SERIAL_RETRY_INTERVAL) {
            printf("[SERIAL] 串口未初始化，尝试重新初始化...\n");
            if (init_serial_port()) {
                printf("[SERIAL] 串口重新初始化成功！\n");
                last_retry_time = current_time;
            } else {
                printf("[SERIAL] 串口重新初始化失败，%d秒后重试\n", SERIAL_RETRY_INTERVAL/1000);
                last_retry_time = current_time;
            }
        }
        return sim_motion_state; // 返回当前状态
    }

    DWORD bytesRead;
    char buffer[2] = {0};

    // 读取串口数据
    if (ReadFile(hSerial, buffer, 1, &bytesRead, NULL)) {
        if (bytesRead > 0) {
            // 处理接收到的数据
            char receivedChar = buffer[0];

            // 过滤掉换行符和回车符
            if (receivedChar == '\n' || receivedChar == '\r') {
                return sim_motion_state; // 保持当前状态
            }

            // 更新运动状态
            uint8_t new_state = (receivedChar == '1') ? 1 : 0;

            // 打印接收到的数据（调试用）
            static uint32_t print_counter = 0;
            print_counter++;
            if (print_counter % 20 == 0) { // 每20次打印一次
                printf("[SERIAL] 获取数据: '%c' (0x%02X),状态: %d\n",
                       receivedChar, (unsigned char)receivedChar, new_state);
                print_counter = 0;
            }

        // 连续运动检测逻辑
        if (new_state == 1) {
            consecutive_motion_count++;
            printf("[MOTION] 连续运动计数: %d/%d\n", consecutive_motion_count, MOTION_THRESHOLD_COUNT);

            // 检查是否在冷却时间内
            if (is_motion_popup_in_cooldown()) {
                uint32_t remaining_seconds = get_remaining_cooldown_seconds();
                printf("[MOTION] 弹窗冷却中，剩余时间: %lu秒\n", remaining_seconds);

                // 如果在冷却时间内，即使达到阈值也不触发弹窗
                // 但保持计数，以便冷却结束后可以快速触发
                if (consecutive_motion_count >= MOTION_THRESHOLD_COUNT) {
                    consecutive_motion_count = MOTION_THRESHOLD_COUNT; // 保持最大值
                }
            }
            // 连续15次检测到运动，且不在冷却时间内，触发弹窗
            else if (!motion_popup_triggered && consecutive_motion_count >= MOTION_THRESHOLD_COUNT) {
                printf("[MOTION] 连续%d次运动检测，触发弹窗！\n", MOTION_THRESHOLD_COUNT);
                motion_popup_triggered = true;

                // 调用弹窗函数
                trigger_motion_popup();

                // 重置计数
                consecutive_motion_count = 0;
            }
        } else {
            // 收到0，重置连续计数
            consecutive_motion_count = 0;
            printf("[MOTION] 静止，重置连续计数.\n");
        }

            sim_motion_state = new_state;
            return new_state;
        }
    } else {
        // 读取失败，检查串口状态
        DCB dcb;
        if (!GetCommState(hSerial, &dcb)) {
            DWORD error = GetLastError();
            printf("[SERIAL] 获取串口状态失败，错误代码: %lu，尝试恢复连接...\n", error);

            // 关闭当前串口并标记为需要重新初始化
            close_serial_port();
            printf("[SERIAL] 已关闭异常串口，将在下次尝试时重新初始化\n");
        }
    }

    return sim_motion_state; // 返回当前状态
}

/**
 * @brief 简化的绝对值函数
 */
int32_t my_abs(int32_t x) {
    return (x < 0) ? -x : x;
}

/**
 * @brief 打印传感器数据（调试用）
 */
void print_sensor_data(void) {
    static uint32_t print_counter = 0;
    print_counter++;

    // 每100次打印一次状态信息
    if (print_counter % 100 == 0) {
        printf("[STATUS] : %d, 计数: %d/%d\n",
               sim_motion_state, consecutive_motion_count, MOTION_THRESHOLD_COUNT);
        print_counter = 0;
    }
}

/**
 * @brief 重置弹窗触发状态
 * 在弹窗关闭后调用，允许重新检测运动
 */
void reset_motion_popup_trigger(void)
{
    motion_popup_triggered = false;
    consecutive_motion_count = 0;
    printf("[MOTION] 弹窗触发器的状态已重置\n");
}
